<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
// 尝试修正模块导入路径，可能需要根据实际项目结构调整
import { useSgesCStore } from './storeSgesCalC'
import { throttle } from 'lodash-es'
import { storeToRefs } from 'pinia'
import * as BABYLON from '@babylonjs/core'
import { Color3, Vector3 } from '@babylonjs/core'
import * as GUI from '@babylonjs/gui'
import { Inspector } from '@babylonjs/inspector'
import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial'
import {
  BrickProceduralTexture, MarbleProceduralTexture, CloudProceduralTexture, FireProceduralTexture
  , StarfieldProceduralTexture, GrassProceduralTexture, RoadProceduralTexture, WoodProceduralTexture
} from '@babylonjs/procedural-textures'

import { SkyMaterial } from '@babylonjs/materials'

const {
  diameter_pillar, heightBlock, widthBlock, lengthBlock, distancePillarWeight,
  heightTower, numOfCellsPerSide, widthGenRegion, numGensPerGroup,
  dHShaft_mm, // 高速轴直径
  dLShaft_mm, // 低速轴直径
  lengthLShaft, // 低速轴长度
  lengthHShaft, // 高速轴长度
  lengthReel, // 卷筒卷线段长度
  diameterReel, // 卷筒直径
  diameterReelSideWall, // 卷筒挡边直径
  widthReelSideWall, // 卷筒挡边宽度
  diameterReelSideBrake, // 碟刹处挡边宽度
  radiusPulleyGroove, // 滑轮绳槽半径，单位m
  DiameterPulley, // 滑轮直径，单位m
  widthPulleySideWall, // 滑轮挡边宽度
  widthSinglePulley, // 单个滑轮宽度
  d1PulleySideWall, // 滑轮挡边直径
  numPulleyPerRope, // 每根绳的滑轮数量
  numRopePerBlock, // 每个重物块的钢丝绳数量
  bPulleyOuter, // 滑轮绳槽口宽度
  gapBlockPulley, gapPulleys, thickPulleyLayer, heightPulleyLayer, thickGenLayer, heightGenLayer, thickRoof,
  lengthPadding, widthPadding, gapReel, rendering
} = storeToRefs(useSgesCStore())
const textColor = '#ffffff'  // 画面中文字的颜色

class BabylonScene {
  scene: BABYLON.Scene
  engine: BABYLON.Engine
  disPW: number// 重物块和柱子的间距
  widthGen: number// 发电机预留宽度
  numPGP: number// 每组发电机的数量
  startX: number// 建模区域的x最小值
  startY: number
  startZ: number
  endX: number
  endY: number
  endZ: number
  x_center: number // 模型中心的x坐标
  y_center: number
  z_center: number
  x_interval: number // x方向重物间距
  z_interval: number // z方向重物间距
  pillarHeight: number // 柱子高度
  distance_LR: number // 平台发电机两侧设备的横向距离（即x方向）
  animationGroup: BABYLON.AnimationGroup | null = null // 储能动画
  brickMaterial: BABYLON.StandardMaterial | null = null
  marbleMaterial: BABYLON.StandardMaterial | null = null
  grassMaterial: BABYLON.StandardMaterial | null = null
  cloudMaterial: BABYLON.StandardMaterial | null = null
  fireMaterial: BABYLON.StandardMaterial | null = null
  roadMaterial: BABYLON.StandardMaterial | null = null
  woodMaterial: BABYLON.StandardMaterial | null = null
  starFieldMaterial: BABYLON.StandardMaterial | null = null

  constructor(private canvas: HTMLCanvasElement) {
    this.engine = new BABYLON.Engine(this.canvas, true)

    this.disPW = Number(distancePillarWeight.value)
    this.widthGen = Number(widthGenRegion.value)
    this.numPGP = Number(numGensPerGroup.value)
    this.startX = -(this.disPW + diameter_pillar.value)
    this.endX = this.widthGen + numOfCellsPerSide.value * (2 * lengthBlock.value + 4 * this.disPW) + (numOfCellsPerSide.value + 1) * 2 * diameter_pillar.value + this.startX
    this.startY = 0
    this.endY = heightTower.value + heightBlock.value / 2 + 10
    this.startZ = this.startX
    this.endZ = this.numPGP * (widthBlock.value + 2 * this.disPW) + (this.numPGP + 1) * diameter_pillar.value + this.startZ
    this.x_center = this.widthGen / 2 + numOfCellsPerSide.value * (lengthBlock.value + 2 * this.disPW) + numOfCellsPerSide.value * diameter_pillar.value - this.disPW
    this.y_center = this.endY / 2
    this.z_center = (this.startX + this.endZ) / 2
    this.x_interval = diameter_pillar.value + 2 * this.disPW + lengthBlock.value
    this.z_interval = widthBlock.value + this.disPW * 2 + diameter_pillar.value
    this.distance_LR = numOfCellsPerSide.value * (lengthBlock.value + 2 * this.disPW) + (numOfCellsPerSide.value + 1) * diameter_pillar.value + this.widthGen
    this.pillarHeight = heightBlock.value + heightTower.value + 25

    this.scene = this.CreateScene()
    this.engine.runRenderLoop(() => {
      this.scene.render()
    })
  }

  CreateScene(): BABYLON.Scene {
    /**
     * 点击创建3D模型按钮时，调用的入口
     */
    const scene = new BABYLON.Scene(this.engine)
    // scene.gravity = new BABYLON.Vector3(0, -9.81, 0);
    new BABYLON.HemisphericLight('light', new BABYLON.Vector3(1, 1, -1)) // 只要创建即可自动加入场景

    this.CreateMaterial() // 材质必须在scene初始化以后才能创建

    this.buildScene(scene)
    scene.collisionsEnabled = true

    const skybox = BABYLON.MeshBuilder.CreateBox('skyBox', { size: 10000.0 }, scene)
    const skyboxMaterial = new BABYLON.StandardMaterial('skyBox', scene)
    skyboxMaterial.backFaceCulling = false
    const files = [
      '/assets/skybox/skybox_px.jpg',
      '/assets/skybox/skybox_py.jpg',
      '/assets/skybox/skybox_pz.jpg',
      '/assets/skybox/skybox_nx.jpg',
      '/assets/skybox/skybox_ny.jpg',
      '/assets/skybox/skybox_nz.jpg'
    ]
    skyboxMaterial.reflectionTexture = BABYLON.CubeTexture.CreateFromImages(files, scene)
    skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE
    skyboxMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0)
    skyboxMaterial.specularColor = new BABYLON.Color3(0, 0, 0)
    skybox.material = skyboxMaterial


    // let hdrTexture = new BABYLON.HDRCubeTexture("/src/assets/027.hdr", scene, 512);

    // Our built-in 'sphere' shape. Params: name, subdivs, size, scene
    // let sphere = BABYLON.MeshBuilder.CreateSphere("sphere1", {
    //   diameter: 10000,
    //   sideOrientation: BABYLON.Mesh.BACKSIDE
    // }, scene);
    //
    // let sphereMtl = new BABYLON.PBRMaterial("sphereMtl", scene);
    // sphereMtl.reflectionTexture = hdrTexture;
    // sphereMtl.disableLighting = true;
    // sphereMtl.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
    // sphere.material = sphereMtl;

    this.showAxis(60, scene)
    this.AddGUIControls(scene)

    return scene
  }

  /***********Create and Draw Axes**************************************/
  showAxis = (size: number, scene: BABYLON.Scene) => {
    const makeTextPlane = (text: string, color: string, size: number) => {
      const dynamicTexture = new BABYLON.DynamicTexture('DynamicTexture', 50, scene, true)
      dynamicTexture.hasAlpha = true
      dynamicTexture.drawText(text, 5, 40, 'bold 36px Arial', color, 'transparent', true)
      const plane = BABYLON.MeshBuilder.CreatePlane('TextPlane', { size, updatable: true }, scene)
      // plane.material = new BABYLON.StandardMaterial("TextPlaneMaterial", scene);
      const Material = new BABYLON.StandardMaterial('TextPlaneMaterial', scene)
      Material.backFaceCulling = false
      Material.specularColor = new BABYLON.Color3(0, 0, 0)
      Material.diffuseTexture = dynamicTexture
      plane.material = Material
      return plane
    }

    const axisX = BABYLON.MeshBuilder.CreateLines('axisX', {
      points: [
        BABYLON.Vector3.Zero(), new BABYLON.Vector3(size, 0, 0), new BABYLON.Vector3(size * 0.95, 0.05 * size, 0),
        new BABYLON.Vector3(size, 0, 0), new BABYLON.Vector3(size * 0.95, -0.05 * size, 0)
      ]
    })
    axisX.color = new BABYLON.Color3(1, 0, 0)
    const xChar = makeTextPlane('X', 'red', size / 10)
    xChar.position = new BABYLON.Vector3(0.9 * size, -0.05 * size, 0)

    const axisY = BABYLON.MeshBuilder.CreateLines('axisY', {
      points: [
        BABYLON.Vector3.Zero(), new BABYLON.Vector3(0, size, 0), new BABYLON.Vector3(-0.05 * size, size * 0.95, 0),
        new BABYLON.Vector3(0, size, 0), new BABYLON.Vector3(0.05 * size, size * 0.95, 0)
      ]
    })
    axisY.color = new BABYLON.Color3(0, 1, 0)
    const yChar = makeTextPlane('Y', 'green', size / 10)
    yChar.position = new BABYLON.Vector3(0, 0.9 * size, -0.05 * size)

    const axisZ = BABYLON.MeshBuilder.CreateLines('axisZ', {
      points: [
        BABYLON.Vector3.Zero(), new BABYLON.Vector3(0, 0, size), new BABYLON.Vector3(0, -0.05 * size, size * 0.95),
        new BABYLON.Vector3(0, 0, size), new BABYLON.Vector3(0, 0.05 * size, size * 0.95)
      ]
    })
    axisZ.color = new BABYLON.Color3(0, 0, 1)
    const zChar = makeTextPlane('Z', 'blue', size / 10)
    zChar.position = new BABYLON.Vector3(0, 0.05 * size, 0.9 * size)
  }

  AddInput(scene: BABYLON.Scene, position: Vector3, speed: number = 0.1) {
    /**
     * 给场景中的character添加WASD等游戏支持
     * 示例： this.AddInput(scene, character.position, 10)
     * @param speed: character移动的速度
     */
    const dsm = new BABYLON.DeviceSourceManager(scene.getEngine())
    dsm.onDeviceConnectedObservable.add((deviceSource) => {
      console.log(`最后连接的设备是${BABYLON.DeviceType[deviceSource.deviceType]}`)
      if (deviceSource.deviceType == BABYLON.DeviceType.Mouse) {
        // deviceSource.onInputChangedObservable.add((eventData) => {
        //   console.log("...")
        // })
      } else if (deviceSource.deviceType == BABYLON.DeviceType.Keyboard) {
        deviceSource.onInputChangedObservable.add((eventData) => {
          if (eventData.code == 'KeyW') {
            position.z += speed
          } else if (eventData.code == 'KeyA') {  // eventData.key=="a" eventData.code=="KeyA" eventData.keyCode==65
            position.x -= speed
          } else if (eventData.code == 'KeyS') {
            position.z -= speed
          } else if (eventData.code == 'KeyD') {
            position.x += speed
          } else if (eventData.code == 'Space') {
            position.y += speed
          } else if (eventData.code == 'KeyX') {
            position.y -= speed
          }
        })

      }
    })
  }

  AddThirdPersonCamera(scene: BABYLON.Scene, canvas: HTMLCanvasElement, speed: number = 1,
                       target = new Vector3(0, 0, 0),
                       position = new Vector3(100, 100, 100)) {
    // 添加第三人称视角的摄像机
    // const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 2.5, 15, new BABYLON.Vector3(0, 0, 0));
    // camera.attachControl(this.canvas, true);
    const camera = new BABYLON.UniversalCamera('defaultCamera', position, scene)
    camera.setTarget(target)
    camera.applyGravity = true
    //设置围绕相机的椭圆 (例如玩家的体积)
    // camera.ellipsoid = new BABYLON.Vector3(0.5, 1, 0.5);
    camera.checkCollisions = true
    // let rotation = camera.rotation
    // let gravity = scene.gravity.y
    // let forwards = new Vector3(Math.sin(rotation.y) / speed, gravity, Math.cos(rotation.y) / speed)
    // let backwards = new Vector3(-Math.sin(rotation.y) / speed, -gravity, -Math.cos(rotation.y) / speed);

    const dsm = new BABYLON.DeviceSourceManager(scene.getEngine())
    dsm.onDeviceConnectedObservable.add((deviceSource) => {
      if (deviceSource.deviceType == BABYLON.DeviceType.Mouse) {
        scene.onPointerObservable.add((pointInfo: BABYLON.PointerInfo, eventState) => {
          // let button = pointInfo.event.button
          // switch (pointInfo.type) {
          //   case BABYLON.PointerEventTypes.POINTERDOWN:
          //     if (button == 0) {  // 左键
          //
          //     } else if (button == 1) { // 中键
          //
          //     } else if (button == 2) { // 右键
          //       // 将camera和character的面向调成一致
          //     }
          //     break;
          //   case BABYLON.PointerEventTypes.POINTERMOVE:
          //     console.log(button)
          //     if (button == -1) { // 无键按下
          //
          //     } else if (button == 0) {  // 左键
          //       console.log("...")
          //     } else if (button == 1) { // 中键
          //       console.log("...")
          //
          //     } else if (button == 2) { // 右键
          //       console.log("...")
          //
          //     }
          //     break;
          //   case BABYLON.PointerEventTypes.POINTERUP:
          //     break;
          //   case BABYLON.PointerEventTypes.POINTERWHEEL:
          //     break;
          //   default:
          //     break;
          // }
          // })
          // deviceSource.onInputChangedObservable.add((eventData, eventState) => {
          //   // 无法获得鼠标按下事件
          //   switch (eventData.button) {  // eventData的类型是PointerEvent
          //     case -1:
          //       break;
          //     case 0: // 左键按下
          //       break;
          //     case 1: // 中键按下
          //       break;
          //     case 2: // 右键按下
          //       break;
          //     default:
          //       console.log("...")
          //   }
        })
      } else if (deviceSource.deviceType == BABYLON.DeviceType.Keyboard) {
        deviceSource.onInputChangedObservable.add((eventData) => {
          if (eventData.code == 'KeyW') {
            // 向前移动
            let directionZ = camera.getDirection(new Vector3(0, 0, 1))  // 用于前后移动
            camera.position = camera.position.add(new Vector3(directionZ.x * speed, directionZ.y * speed, directionZ.z * speed))
            camera.target = camera.target.add(new Vector3(directionZ.x * speed, directionZ.y * speed, directionZ.z * speed))
          } else if (eventData.code == 'KeyD') {  // eventData.key=="a" eventData.code=="KeyA" eventData.keyCode==65
            let directionX = camera.getDirection(new Vector3(1, 0, 0))  // 用于左右移动
            camera.position = camera.position.add(new Vector3(directionX.x * speed, directionX.y * speed, directionX.z * speed))
            camera.target = camera.target.add(new Vector3(directionX.x * speed, directionX.y * speed, directionX.z * speed))
          } else if (eventData.code == 'KeyS') {
            let directionZ = camera.getDirection(new Vector3(0, 0, 1))  // 用于前后移动
            camera.position = camera.position.subtract(new Vector3(directionZ.x * speed, directionZ.y * speed, directionZ.z * speed))
            camera.target = camera.target.subtract(new Vector3(directionZ.x * speed, directionZ.y * speed, directionZ.z * speed))
          } else if (eventData.code == 'KeyA') {
            let directionX = camera.getDirection(new Vector3(1, 0, 0))  // 用于左右移动
            camera.position = camera.position.subtract(new Vector3(directionX.x * speed, directionX.y * speed, directionX.z * speed))
            camera.target = camera.target.subtract(new Vector3(directionX.x * speed, directionX.y * speed, directionX.z * speed))
          } else if (eventData.code == 'Space') {
            let directionY = camera.getDirection(new Vector3(0, 1, 0))  // 用于上下移动
            camera.position = camera.position.add(new Vector3(directionY.x * speed, directionY.y * speed, directionY.z * speed))
            camera.target = camera.target.add(new Vector3(directionY.x * speed, directionY.y * speed, directionY.z * speed))
          } else if (eventData.code == 'KeyX') {
            let directionY = camera.getDirection(new Vector3(0, 1, 0))  // 用于上下移动
            camera.position = camera.position.subtract(new Vector3(directionY.x * speed, directionY.y * speed, directionY.z * speed))
            camera.target = camera.target.subtract(new Vector3(directionY.x * speed, directionY.y * speed, directionY.z * speed))
          }
        })
      }
    })
    // let operation = "R"
    // switch (operation) {
    //   case "R":
    //     camera.position = new Vector3();
    //     camera.setTarget(new Vector3());
    // }
    camera.attachControl(true)
  }

  buildPillar(disPW: number, widthGen: number, numPGP: number) {

    const buildPillarAtZ = (z) => {
      // 绘制柱子
      const pillar = BABYLON.MeshBuilder.CreateCylinder(`承重柱${z}_0`, {
        height: this.pillarHeight,
        diameter: diameter_pillar.value
      })

      // const material = new BABYLON.StandardMaterial("boxMat");
      // // genMat.diffuseTexture = new BABYLON.Texture("/src/assets/concrete.jpg");
      // material.diffuseColor = BABYLON.Color3.Red()
      // pillar.material = this.starFieldMaterial

      pillar.position = new Vector3(-disPW - diameter_pillar.value / 2, this.pillarHeight / 2, z * this.z_interval - disPW - diameter_pillar.value / 2)
      for (let i = 1; i < numOfCellsPerSide.value + 1; i++) {
        let pillar1 = pillar.createInstance(`承重柱${z}_${i}`)
        pillar1.parent = pillar
        pillar1.position = new Vector3(this.x_interval * i, 0, 0)
      }

      const pillar_side = pillar.createInstance(`承重柱${z}_${numOfCellsPerSide.value + 1}`)
      const pillar1x = (numOfCellsPerSide.value + 1) * diameter_pillar.value + 2 * numOfCellsPerSide.value * disPW + numOfCellsPerSide.value * lengthBlock.value + widthGen
      pillar_side.parent = pillar
      pillar_side.position = new Vector3(
        pillar1x,
        0,
        0
      )
      for (let i = 1; i < numOfCellsPerSide.value + 1; i++) {
        let pillar1 = pillar.createInstance(`承重柱${z}_${i + numOfCellsPerSide.value + 1}`)
        pillar1.parent = pillar
        pillar1.position = new Vector3(this.x_interval * i + pillar1x, 0, 0)
      }
    }

    for (let j = 0; j < numPGP + 1; j++) {
      buildPillarAtZ(j)
    }
  }

  buildBlocks() {
    /**
     * 绘制重物块
     */
    let block = BABYLON.MeshBuilder.CreateBox(`重物块0_0`, {
      height: heightBlock.value,
      width: lengthBlock.value,
      depth: widthBlock.value
    })  // 创建重物块
    const boxMat = new BABYLON.StandardMaterial('boxMat')
    boxMat.diffuseTexture = new BABYLON.Texture('/assets/concrete.jpg')
    block.material = boxMat // this.fireMaterial
    block.position = new Vector3(lengthBlock.value / 2, heightBlock.value / 2, widthBlock.value / 2)
    // 绘制动滑轮
    // numPulleyPerRope, // 每根绳的滑轮数量
    // numRopePerBlock, // 没个重物块的钢丝绳数量
    // widthSinglePulley, // 单个滑轮宽度
    //     d1PulleySideWall, // 滑轮挡边直径
    //     numPulleyPerRope, // 每根绳的滑轮数量
    //     numRopePerBlock, // 每个重物块的钢丝绳数量
    // bPulleyOuter
    const dGroove = radiusPulleyGroove.value * 2
    const dSide = (bPulleyOuter.value - dGroove) / 2
    const dxSloop = (widthSinglePulley.value - bPulleyOuter.value) / 2
    const profile = [
      new Vector3(0, 0, 0),
      new Vector3(d1PulleySideWall.value / 2, 0, 0),
      new Vector3(d1PulleySideWall.value, dxSloop, 0),
      new Vector3(d1PulleySideWall.value, dSide + dxSloop, 0),
      new Vector3(DiameterPulley.value, dSide + dxSloop, 0),
      new Vector3(DiameterPulley.value, dSide + dxSloop + dGroove, 0),
      new Vector3(d1PulleySideWall.value, dSide + dxSloop + dGroove, 0),
      new Vector3(d1PulleySideWall.value, 2 * dSide + dxSloop + dGroove, 0),
      new Vector3(d1PulleySideWall.value / 2, widthSinglePulley.value, 0),
      new Vector3(0, widthSinglePulley.value, 0)
    ]

    let pulley = BABYLON.MeshBuilder.CreateLathe('滑轮', { shape: profile, sideOrientation: BABYLON.Mesh.DEFAULTSIDE })
    pulley.rotation.z = Math.PI / 2
    pulley.bakeCurrentTransformIntoVertices()
    let pulleys = [pulley]
    for (let i = 1; i < numPulleyPerRope.value; i++) {
      const pulley_ = pulley.clone()
      pulley_.position.x -= widthSinglePulley.value * i
      pulleys.push(pulley_)
    }
    // 调用 MergeMeshes 方法合并网格，该方法可能返回 null，因此需要进行空值检查
    let mergedMesh = BABYLON.Mesh.MergeMeshes(pulleys)
    if (mergedMesh) {
      pulley = mergedMesh
    } else {
      console.error('网格合并失败，返回值为 null')
    }
    pulley.position.x += widthSinglePulley.value * numPulleyPerRope.value / 2
    pulley.bakeCurrentTransformIntoVertices()
    const distance = (lengthBlock.value - numRopePerBlock.value * widthSinglePulley.value * numPulleyPerRope.value) / (numRopePerBlock.value - 1) + widthSinglePulley.value * numPulleyPerRope.value
    pulleys = [pulley]
    for (let i = 1; i < numRopePerBlock.value; i++) {
      const pulley_ = pulley.clone()
      pulley_.position.x += distance * i
      pulleys.push(pulley_)
    }
    // 处理 MergeMeshes 可能返回 null 的情况，避免类型错误
    mergedMesh = BABYLON.Mesh.MergeMeshes(pulleys)
    if (mergedMesh) {
      pulley = mergedMesh
    } else {
      console.error('网格合并失败，返回值为 null')
      // 可以根据需求添加默认值或其他处理逻辑，这里简单保持原 pulley 不变
    }
    pulley.position.x = widthSinglePulley.value * numPulleyPerRope.value / 2
    pulley.position.x -= ((widthSinglePulley.value * numPulleyPerRope.value * numRopePerBlock.value) + (numRopePerBlock.value - 1) * (distance - widthSinglePulley.value * numPulleyPerRope.value)) / 2
    pulley.bakeCurrentTransformIntoVertices()

    const blocks = [block]
    pulleys = [pulley]
    for (let i = 1; i < numOfCellsPerSide.value; i++) {
      const block_ = block.clone(`重物块${i}`)
      block_.position.x += this.x_interval * i
      const pulley_ = pulley.clone()
      pulley_.position.x += this.x_interval * i
      blocks.push(block_)
      pulleys.push(pulley_)
    }
    // 由于 MergeMeshes 可能返回 null，需要进行空值检查
    let mergedBlock = BABYLON.Mesh.MergeMeshes(blocks, true, true)
    if (mergedBlock) {
      block = mergedBlock
    } else {
      console.error('合并网格失败，返回值为 null')
    }
    // 处理 MergeMeshes 可能返回 null 的情况，避免类型不匹配错误
    mergedMesh = BABYLON.Mesh.MergeMeshes(pulleys, true, true)
    if (mergedMesh) {
      pulley = mergedMesh
    } else {
      console.error('网格合并失败，返回值为 null')
    }

    pulley.position.x = lengthBlock.value / 2
    pulley.position.z = widthBlock.value / 2
    pulley.position.y = heightBlock.value + d1PulleySideWall.value * 1.2
    // const material = new BABYLON.StandardMaterial("material")
    // material.diffuseColor = new Color3(186, 110, 64)
    pulley.material = this.woodMaterial

    // 合并网格，由于 MergeMeshes 可能返回 null，需要进行空值检查
    mergedBlock = BABYLON.Mesh.MergeMeshes([block, pulley], true, true, undefined, false, true)
    if (mergedBlock) {
      block = mergedBlock
    } else {
      console.error('重物块和滑轮网格合并失败，返回值为 null')
    }

    let block_ = block.clone()
    block_.position.x += this.distance_LR
    mergedMesh = BABYLON.Mesh.MergeMeshes([block, block_], true, true, undefined, false, true)// 此时，block为一行中所有的重物块
    if (mergedMesh) {
      block = mergedMesh
    } else {
      console.error('合并重物块网格时返回 null，无法更新 block 变量')
    }
    block.name = '重物块0'
    //
    for (let j = 1; j < this.numPGP; j++) {
      block_ = block.clone(`重物块${j}`)
      block_.position.z += this.z_interval * j
    }
  }

  buildTopLayer(disPW: number, widthGen: number, numPGP: number) {
    /**
     * 创建顶部发电机设备层
     * @param disPW: 重物块与柱子之间的距离
     * @param widthGen: 发电机行预留的宽度
     * @param numPGP: 每组中发电机的数量
     */
      // 绘制顶板
    const GenLayerStartY = heightTower.value + heightBlock.value + 15
    const GenLayerEndY = heightTower.value + heightBlock.value + 15.4
    const genLayer = BABYLON.MeshBuilder.CreateBox('设备层地面', {
      width: (this.endX - this.startX) * 1.2,
      height: GenLayerEndY - GenLayerStartY,
      depth: (this.endZ - this.startZ) * 1.2
    })

    genLayer.material = this.marbleMaterial

    genLayer.position = new Vector3(this.x_center, (GenLayerStartY + GenLayerEndY) / 2, this.z_center)

    const roof = BABYLON.MeshBuilder.CreateBox('塔顶', {
      width: this.endX - this.startX,
      height: 0.2,
      depth: this.endZ - this.startZ
    })
    roof.material = this.grassMaterial
    roof.position = new Vector3(this.x_center, this.pillarHeight, this.z_center)

  }

  buildGenerators(disPW: number, widthGen: number, numPGP: number, diameter: number) {
    const gen = BABYLON.MeshBuilder.CreateCylinder('电动发电机0', {
      diameter: diameter,
      height: diameter
    })
    const genMat = new BABYLON.StandardMaterial('boxMat')
    // genMat.diffuseTexture = new BABYLON.Texture("/src/assets/concrete.jpg");
    genMat.diffuseColor = BABYLON.Color3.Blue()
    gen.material = genMat
    gen.position = new Vector3(
      this.x_center,
      heightTower.value + heightBlock.value + 15.4 + diameter,
      widthBlock.value / 2)
    gen.rotation.z = Math.PI / 2

    for (let j = 1; j < numPGP; j++) {
      const gen1 = gen.createInstance(`电动发电机${j}`)
      gen1.parent = gen
      gen1.position = new Vector3(0, 0, this.z_interval * j)
      gen1.rotation.z = 0
    }
  }

  buildShafts(disPW: number, widthGen: number, numPGP: number, diameter: number) {
    /**
     * 创建轴系
     * @param disPW: 重物块和柱子的距离
     * @param widthGen: 发电机预留宽度
     * @param numPGP: 每组发电机数量
     * @param diameter: 发电机直径
     */
    const y_center_topDevice = heightTower.value + heightBlock.value + 15.4 + diameter
    // ---------------------------- 绘制高速轴 --------------------------------------------------
    const shaftHLeft = BABYLON.MeshBuilder.CreateCylinder('shaftHLeft', {
      diameter: dHShaft_mm.value / 1000,
      height: lengthHShaft.value
    })
    const material = new BABYLON.StandardMaterial('boxMat')
    material.diffuseColor = BABYLON.Color3.Green()
    shaftHLeft.material = material
    shaftHLeft.position = new Vector3(
      this.x_center - lengthHShaft.value / 2,
      y_center_topDevice,
      widthBlock.value / 2)
    shaftHLeft.rotation.z = Math.PI / 2
    const shaftHRight = shaftHLeft.clone('shaftHRight')
    shaftHRight.position = new Vector3(
      this.x_center + lengthHShaft.value / 2,
      y_center_topDevice,
      widthBlock.value / 2
    )
    // shaftHRight.rotation.z = Math.PI / 2
    const shaftH = BABYLON.Mesh.MergeMeshes([shaftHLeft, shaftHRight])
    shaftH!.name = '高速轴0'
    // ---------------------------- 绘制高速轴 --------------------------------------------------

    // ---------------------------- 绘制低速轴 --------------------------------------------------
    // 单个重物的低速轴长度*重物数量+(重物数量+1)*柱子直径+0.25倍的发电机预留宽度，认为发电机上预留的ShaftL0长度和高速轴长度一样
    const lengthLShaftPerSide = lengthLShaft.value * numOfCellsPerSide.value + (numOfCellsPerSide.value + 1) * diameter_pillar.value + Number(widthGenRegion.value) / 4
    const shaftLLeft = BABYLON.MeshBuilder.CreateCylinder('shaftLLeft', {
      diameter: dLShaft_mm.value / 1000,
      height: lengthLShaftPerSide
    })
    shaftLLeft.position = new Vector3(
      this.x_center - lengthHShaft.value - lengthLShaftPerSide / 2,
      y_center_topDevice,
      widthBlock.value / 2
    )
    shaftLLeft.rotation.z = Math.PI / 2
    const shaftLRight = shaftLLeft.clone('shaftLRight')
    shaftLRight.position = new Vector3(
      this.x_center + lengthHShaft.value + lengthLShaftPerSide / 2,
      y_center_topDevice,
      widthBlock.value / 2
    )
    const shaftL = BABYLON.Mesh.MergeMeshes([shaftLLeft, shaftLRight])
    // ---------------------------- 绘制低速轴 --------------------------------------------------

    // ------------------------------ 绘制卷筒 --------------------------------------------------
    // lengthReel, // 卷筒卷线段长度
    //     diameterReel, // 卷筒直径
    //     diameterReelSideWall, // 卷筒挡边直径
    //     widthReelSideWall, // 卷筒挡边宽度
    //     diameterReelSideBrake, // 碟刹处挡边宽度
    const radiusReelSideBrake = diameterReelSideBrake.value / 2
    const radiusReel = diameterReel.value / 2
    const radiusReelSideWall = diameterReelSideWall.value / 2
    const profile = [
      new Vector3(0, 0, 0),
      new Vector3(radiusReelSideBrake, 0, 0),
      new Vector3(radiusReelSideBrake, widthReelSideWall.value, 0),
      new Vector3(radiusReel, widthReelSideWall.value, 0),
      new Vector3(radiusReel, lengthReel.value + widthReelSideWall.value, 0),
      new Vector3(radiusReelSideWall, lengthReel.value + widthReelSideWall.value, 0),
      new Vector3(radiusReelSideWall, lengthReel.value + widthReelSideWall.value * 2, 0),
      new Vector3(radiusReel, lengthReel.value + widthReelSideWall.value * 2, 0),
      new Vector3(radiusReel, 2 * (lengthReel.value + widthReelSideWall.value), 0),
      new Vector3(radiusReelSideBrake, 2 * (lengthReel.value + widthReelSideWall.value), 0),
      new Vector3(radiusReelSideBrake, 2 * lengthReel.value + 3 * widthReelSideWall.value, 0),
      new Vector3(0, 2 * lengthReel.value + 3 * widthReelSideWall.value, 0)
    ]
    const reel1 = BABYLON.MeshBuilder.CreateLathe('reel1', {
      shape: profile,
      sideOrientation: BABYLON.Mesh.DEFAULTSIDE
    })
    const lengthReel1 = lengthReel.value * 2 + widthReelSideWall.value * 3

    reel1.position.y = -lengthReel1 / 2
    reel1.bakeCurrentTransformIntoVertices()
    reel1.rotation.z = Math.PI / 2
    reel1.bakeCurrentTransformIntoVertices()
    const blockL1CenterX = this.x_center - widthGen / 2 - diameter_pillar.value - disPW - lengthBlock.value / 2
    reel1.position = new Vector3(
      blockL1CenterX - lengthReel1 / 2,
      y_center_topDevice,
      widthBlock.value / 2
    )
    const reel2 = reel1.clone('reel2')
    reel2.position = new Vector3(
      blockL1CenterX + lengthReel1 / 2,
      y_center_topDevice,
      widthBlock.value / 2
    )
    let reel = BABYLON.Mesh.MergeMeshes([reel1, reel2])
    let reels: BABYLON.Mesh[] = []
    reels.push(reel!)
    for (let i = 1; i < numOfCellsPerSide.value; i++) {
      reels.push(reel!.clone('reel'))
      reels[i].position = reel!.position.add(new Vector3(
        -this.x_interval * i, 0, 0
      ))
    }
    reel = BABYLON.Mesh.MergeMeshes(reels)

    const reel3 = reel!.clone('reel')
    reel3.position.x += this.distance_LR
    reel = BABYLON.Mesh.MergeMeshes([reel!, reel3, shaftL!])
    reel!.name = '卷筒轴0'

    for (let j = 1; j < numPGP; j++) {
      const reel1 = reel!.createInstance(`卷筒轴${j}`)
      reel1.position.z += this.z_interval * j
      const shaftH1 = shaftH!.createInstance(`高速轴${j}`)
      shaftH1.position.z += this.z_interval * j
    }
  }

  buildLoadLayer() {
    /**
     * 创建顶部动滑轮层
     *
     */
      // 获取模型参数，高度，厚度，大小等
    const height = heightTower.value + heightBlock.value + 10
    const thick = 0.4

    // 根据参数创建模型
    let layer = BABYLON.MeshBuilder.CreateBox('滑轮层地面', {
      width: this.endX - this.startX,
      height: thick,
      depth: this.endZ - this.startZ
    })
    layer.position = new Vector3(this.x_center, height, this.z_center)

  }


  buildScene = (scene: BABYLON.Scene) => {
    /**
     * 构建重力储能应用场景
     */
    this.buildBlocks() // 创建重物块
    this.buildPillar(this.disPW, this.widthGen, this.numPGP) // 创建柱子
    this.buildTopLayer(this.disPW, this.widthGen, this.numPGP) // 创建发电机层的支撑板
    this.buildGenerators(this.disPW, this.widthGen, this.numPGP, widthBlock.value / 2) // 创建发电机
    this.buildShafts(this.disPW, this.widthGen, this.numPGP, widthBlock.value / 2) // 创建传动轴系
    this.buildLoadLayer()


    const ground = BABYLON.MeshBuilder.CreateGround('ground', { width: 400, height: 400 })
    // const music = new BABYLON.Sound("cello", "https://playground.babylonjs.com/sounds/bounce.wav", scene, null, { loop: true, autoplay: true });
    ground.position = new Vector3(100, 0, 100)
    const boxMat1 = new BABYLON.StandardMaterial('boxMat')
    boxMat1.diffuseTexture = new BABYLON.Texture('/src/assets/grass.png')
    ground.material = this.brickMaterial
    // this.AddInput(scene, box, 0.1)
    ground.checkCollisions = true

    const _xz = this.x_center > this.z_center ? this.x_center * 3 : this.z_center * 3
    this.AddThirdPersonCamera(scene, this.canvas, 1,
      new Vector3(this.x_center, this.y_center * 1.1, this.z_center),  // target
      new Vector3(-_xz, this.endY * 1.2, -_xz)) // position

    return scene
  }

  CreateMaterial() {
    // 创建材质，
    // 大理石材质
    this.marbleMaterial = new BABYLON.StandardMaterial('marbleMat')
    const marbleTexture = new MarbleProceduralTexture('marbleTex', 512)
    marbleTexture.numberOfTilesWidth = 6
    marbleTexture.numberOfTilesHeight = 10
    this.marbleMaterial.diffuseTexture = marbleTexture

    // 砖块材质
    this.brickMaterial = new BABYLON.StandardMaterial('brick')
    const brickTexture = new BrickProceduralTexture('brickTexture', 2048)
    brickTexture.numberOfBricksWidth = 60
    brickTexture.numberOfBricksHeight = 100
    this.brickMaterial.diffuseTexture = brickTexture

    this.grassMaterial = new BABYLON.StandardMaterial('grass')
    const grassTexture = new GrassProceduralTexture('grassTexture', 512)
    // grassTexture.grassColors = new Color3(134, 198, 118);
    this.grassMaterial.diffuseTexture = grassTexture

    this.woodMaterial = new BABYLON.StandardMaterial('wood')
    const woodTexture = new WoodProceduralTexture('woodTexture', 512)
    // woodTexture.woodColor =
    this.woodMaterial.diffuseTexture = woodTexture

    this.starFieldMaterial = new BABYLON.StandardMaterial('starFieldMaterial')
    this.starFieldMaterial.diffuseTexture = new StarfieldProceduralTexture('starFieldMaterial', 512)

    this.roadMaterial = new BABYLON.StandardMaterial('road')
    this.roadMaterial.diffuseTexture = new RoadProceduralTexture('roadMaterial', 512)

    this.fireMaterial = new BABYLON.StandardMaterial('fireMaterial')
    this.fireMaterial.diffuseTexture = new FireProceduralTexture('fireMaterial', 512)
  }


  startCharging() {
    /**
     *
     */
    const charging1 = new BABYLON.Animation('储能过程', 'position.y', 10, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE)
    const charging2 = new BABYLON.Animation('储能过程', 'position.y', 10, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE)

    charging1.setKeys([
      {
        frame: 0,
        value: 0
      }, {
        frame: 10,
        value: 0
      },
      {
        frame: 310,
        value: heightTower.value
      },
      {
        frame: 620,
        value: heightTower.value
      }
    ])
    charging2.setKeys([
      {
        frame: 0,
        value: 0
      },
      {
        frame: 310,
        value: 0
      },
      {
        frame: 610,
        value: heightTower.value
      }, {
        frame: 620,
        value: heightTower.value
      }
    ])
    this.animationGroup = new BABYLON.AnimationGroup('Group1')

    if (this.numPGP % 2 == 0) {
      const num = this.numPGP / 2
      for (let i = 0; i < num / 2; i++) {
        this.animationGroup.addTargetedAnimation(charging2, this.scene.getMeshByName(`重物块${i}`))
        this.animationGroup.addTargetedAnimation(charging2, this.scene.getMeshByName(`重物块${this.numPGP - i - 1}`))
      }
      for (let i = Math.floor(num / 2); i < num; i++) {
        this.animationGroup.addTargetedAnimation(charging1, this.scene.getMeshByName(`重物块${i}`))
        this.animationGroup.addTargetedAnimation(charging1, this.scene.getMeshByName(`重物块${this.numPGP - i - 1}`))
      }
      this.animationGroup.normalize(0, 620)
      this.animationGroup.start(true)

    }
  }

  startLooping() {
    /**
     *
     */
    const charging1 = new BABYLON.Animation('储能过程', 'position.y', 10, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE)
    const charging2 = new BABYLON.Animation('储能过程', 'position.y', 10, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE)

    charging1.setKeys([
      {
        frame: 0,
        value: 0
      }, {
        frame: 10,
        value: 0
      },
      {
        frame: 310,
        value: heightTower.value
      },
      {
        frame: 930,
        value: heightTower.value
      },
      {
        frame: 1230,
        value: 0
      }, {
        frame: 1240,
        value: 0
      }
    ])
    charging2.setKeys([
      {
        frame: 0,
        value: 0
      },
      {
        frame: 310,
        value: 0
      },
      {
        frame: 610,
        value: heightTower.value
      }, {
        frame: 620,
        value: heightTower.value
      },
      {
        frame: 630,
        value: heightTower.value
      }, {
        frame: 930,
        value: 0
      }, {
        frame: 1240,
        value: 0
      }
    ])
    this.animationGroup = new BABYLON.AnimationGroup('Group1')

    if (this.numPGP % 2 == 0) {
      const num = this.numPGP / 2
      for (let i = 0; i < num / 2; i++) {
        this.animationGroup.addTargetedAnimation(charging2, this.scene.getMeshByName(`重物块${i}`))
        this.animationGroup.addTargetedAnimation(charging2, this.scene.getMeshByName(`重物块${this.numPGP - i - 1}`))
      }
      for (let i = Math.floor(num / 2); i < num; i++) {
        this.animationGroup.addTargetedAnimation(charging1, this.scene.getMeshByName(`重物块${i}`))
        this.animationGroup.addTargetedAnimation(charging1, this.scene.getMeshByName(`重物块${this.numPGP - i - 1}`))
      }
      this.animationGroup.normalize(0, 1240)
      this.animationGroup.start(true, 1, 0, 1240)
    }
  }

  startDisCharging() {
    /**
     *
     */
    const charging1 = new BABYLON.Animation('储能过程', 'position.y', 10, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE)
    const charging2 = new BABYLON.Animation('储能过程', 'position.y', 10, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE)

    charging1.setKeys([
      {
        frame: 0,
        value: 0
      }, {
        frame: 10,
        value: 0
      },
      {
        frame: 310,
        value: heightTower.value
      },
      {
        frame: 620,
        value: heightTower.value
      }
    ])
    charging2.setKeys([
      {
        frame: 0,
        value: 0
      },
      {
        frame: 310,
        value: 0
      },
      {
        frame: 610,
        value: heightTower.value
      }, {
        frame: 620,
        value: heightTower.value
      }
    ])
    this.animationGroup = new BABYLON.AnimationGroup('Group1')

    if (this.numPGP % 2 == 0) {
      const num = this.numPGP / 2
      for (let i = 0; i < num / 2; i++) {
        this.animationGroup.addTargetedAnimation(charging2, this.scene.getMeshByName(`重物块${i}`))
        this.animationGroup.addTargetedAnimation(charging2, this.scene.getMeshByName(`重物块${this.numPGP - i - 1}`))
      }
      for (let i = Math.floor(num / 2); i < num; i++) {
        this.animationGroup.addTargetedAnimation(charging1, this.scene.getMeshByName(`重物块${i}`))
        this.animationGroup.addTargetedAnimation(charging1, this.scene.getMeshByName(`重物块${this.numPGP - i - 1}`))
      }
      this.animationGroup.normalize(0, 620)
      this.animationGroup.start(true, 1, 620, 0)
    }
  }

  AddGUIControls(scene: BABYLON.Scene) {
    const advancedTexture = GUI.AdvancedDynamicTexture.CreateFullscreenUI('myUI')

    const button2 = GUI.Button.CreateSimpleButton('but2', '调试信息')
    button2.width = '100px'
    button2.height = '30px'
    button2.cornerRadius = 5
    button2.color = textColor

    button2.onPointerUpObservable.add(function() {
      Inspector.Show(scene, { embedMode: true })
    })
    button2.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_LEFT
    button2.verticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_TOP
    advancedTexture.addControl(button2)

    const button1 = GUI.Button.CreateSimpleButton('but1', '前视')
    button1.width = '100px'
    button1.height = '30px'
    button1.cornerRadius = 5
    button1.color = textColor
    button1.onPointerUpObservable.add(function() {
      const camera = scene.getCameraByName('defaultCamera') as BABYLON.UniversalCamera
      camera.position = new Vector3(0, 0, -200)
      camera.setTarget(new Vector3(0, heightTower.value / 2, 0))
    })
    button1.left = '100px'
    button1.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_LEFT
    button1.verticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_TOP
    advancedTexture.addControl(button1)


    const button3 = GUI.Button.CreateSimpleButton('but3', '上视')
    button3.width = '100px'
    button3.height = '30px'
    button3.cornerRadius = 5
    button3.color = textColor
    button3.onPointerUpObservable.add(function() {
      const camera = scene.getCameraByName('defaultCamera') as BABYLON.UniversalCamera
      camera.position = new Vector3(0, 200, 0)
      camera.setTarget(new Vector3(0, 0, 0))
    })
    button3.left = '200px'
    button3.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_LEFT
    button3.verticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_TOP
    advancedTexture.addControl(button3)

    const button4 = GUI.Button.CreateSimpleButton('but4', '右视')
    button4.width = '100px'
    button4.height = '30px'
    button4.cornerRadius = 5
    button4.color = textColor
    button4.onPointerUpObservable.add(function() {
      const camera = scene.getCameraByName('defaultCamera') as BABYLON.UniversalCamera
      camera.position = new Vector3(0, 200, 0)
      camera.setTarget(new Vector3(0, 0, 0))
    })
    button4.left = '300px'
    button4.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_LEFT
    button4.verticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_TOP
    advancedTexture.addControl(button4)

    const button5 = GUI.Button.CreateSimpleButton('but5', '正交视图')
    button5.width = '100px'
    button5.height = '30px'
    button5.cornerRadius = 5
    button5.color = textColor
    button5.onPointerUpObservable.add(function() {
      const camera = scene.getCameraByName('defaultCamera') as BABYLON.UniversalCamera
      camera.mode = BABYLON.Camera.ORTHOGRAPHIC_CAMERA            //指定相机的类型
      const ratio = window.innerHeight / window.innerWidth     //计算屏幕宽高比
      camera.orthoLeft = 200                        //设置近平面的左侧边界
      camera.orthoRight = -200                      //设置近平面的右侧边界
      camera.orthoTop = 200 * ratio                   //设置近平面的顶部边界
      camera.orthoBottom = -200 * ratio               //设置近平面的底部边界
      camera.attachControl(canvas, true)
    })
    button5.left = '400px'
    button5.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_LEFT
    button5.verticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_TOP
    advancedTexture.addControl(button5)

    const button6 = GUI.Button.CreateSimpleButton('but6', '透视图')
    button6.width = '100px'
    button6.height = '30px'
    button6.cornerRadius = 5
    button6.color = textColor
    button6.onPointerUpObservable.add(function() {
      const camera = scene.getCameraByName('defaultCamera') as BABYLON.UniversalCamera
      camera.mode = BABYLON.Camera.PERSPECTIVE_CAMERA
    })
    button6.left = '500px'
    button6.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_LEFT
    button6.verticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_TOP
    advancedTexture.addControl(button6)

    const button7 = GUI.Button.CreateSimpleButton('but7', '开始储能')
    button7.width = '100px'
    button7.height = '30px'
    button7.cornerRadius = 5
    button7.color = textColor
    button7.onPointerUpObservable.add(() => {
      this.startCharging()
    })
    button7.left = '0px'
    button7.top = '30px'
    button7.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_LEFT
    button7.verticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_TOP
    advancedTexture.addControl(button7)

    const button8 = GUI.Button.CreateSimpleButton('but8', '开始释能')
    button8.width = '100px'
    button8.height = '30px'
    button8.cornerRadius = 5
    button8.color = textColor
    button8.onPointerUpObservable.add(() => {
      this.startDisCharging()
    })
    button8.left = '100px'
    button8.top = '30px'
    button8.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_LEFT
    button8.verticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_TOP
    advancedTexture.addControl(button8)

    const button9 = GUI.Button.CreateSimpleButton('but9', '循环储释')
    button9.width = '100px'
    button9.height = '30px'
    button9.cornerRadius = 5
    button9.color = textColor
    button9.onPointerUpObservable.add(() => {
      this.startLooping()
    })
    button9.left = '200px'
    button9.top = '30px'
    button9.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_LEFT
    button9.verticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_TOP
    advancedTexture.addControl(button9)

    const button10 = GUI.Button.CreateSimpleButton('but10', '紧急停机')
    button10.width = '100px'
    button10.height = '30px'
    button10.cornerRadius = 5
    button10.color = textColor
    button10.onPointerUpObservable.add((eventData, eventState) => {
      if (this.animationGroup?.isPlaying) {
        this.animationGroup.pause()
        eventState.target.textBlock.text = '继续运行'
      } else {
        this.animationGroup!.restart()
        eventState.target.textBlock.text = '紧急停机'
      }
    })
    button10.left = '300px'
    button10.top = '30px'
    button10.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_LEFT
    button10.verticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_TOP
    advancedTexture.addControl(button10)

    const button11 = GUI.Button.CreateSimpleButton('but11', '渲染全站')
    button11.width = '100px'
    button11.height = '30px'
    button11.cornerRadius = 5
    button11.color = textColor
    button11.onPointerUpObservable.add((eventData, eventState) => {

    })
    button11.left = '400px'
    button11.top = '30px'
    button11.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_LEFT
    button11.verticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_TOP
    advancedTexture.addControl(button11)
  }
}


const canvas = ref()
const clientWidth = ref(window.innerWidth)
const clientHeight = ref(window.innerHeight)
let babylonScene: BabylonScene | null = null
onMounted(() => {
  // const canvas = document.querySelector("canvas")
  babylonScene = new BabylonScene(canvas.value)
  resizeObserver.observe(canvas.value)
})

onUnmounted(() => {
  // 停止监听 canvas 尺寸变化
  resizeObserver.disconnect()

  // 销毁 BabylonScene 实例及其资源
  if (babylonScene) {
    const { scene, engine } = babylonScene
    if (scene) {
      scene.dispose() // 释放场景资源
    }
    if (engine) {
      engine.dispose() // 释放引擎资源
    }
    babylonScene = null
  }
})


const resizeObserver = new ResizeObserver(throttle(() => {
  /**
   * 在canvas大小改变时，自动重新渲染模型视野大小，如果不加该方法，则只是canvas大小变化，而模型会挤压变形，不能保持原模型实际的长宽比
   */
  try {
    clientWidth.value = canvas.value.clientWidth
    clientHeight.value = canvas.value.clientHeight
  } catch (e) {

  }
}, 500))

defineExpose({})
</script>

<template>
  <canvas ref="canvas" :width="clientWidth" :height="clientHeight" class="canvas"></canvas>
</template>

<style scoped>
.canvas {
  width: 100%;
  height: 100%;
}
</style>